/** ****************************************************************************
@addtogroup UART
@{
*******************************************************************************/

#ifndef _UART_H_
#define _UART_H_

#ifdef __cplusplus
extern "C" {
#endif

#include "std_type.h"
#include "driver/uart.h"


// 兼容 STM SDK
#define USART_WordLength_TypeDef uart_word_length_t
#define USART_StopBits_TypeDef   uart_stop_bits_t
#define USART_Parity_TypeDef     uart_parity_t

// forward
struct stUARTPort;

typedef void (*FUNC_UART_onRxChar)(struct stUARTPort* uart, uint8_t ch, void *cookie);
typedef void (*FUNC_UART_onTxComplete)(struct stUARTPort* uart, void *cookie);

/// 串口数据结构
typedef struct stUARTPort {
	uart_port_t port;
	int pinTxd;
	int pinRxd;
	void *led;
	FUNC_void_u8 txe;
	uart_mode_t mode;
	uart_config_t config;
	FUNC_UART_onRxChar onRxChar;
	void *onRxCharCookie;
	bool enableRxHandler;
	QueueHandle_t queue;		///< 串口事件队列
} UARTPort_t;

/// UART 句柄
typedef UARTPort_t* UARTPort;

/// ESP32 有 3 个 UART
extern UARTPort UARTPort0;
extern UARTPort UARTPort1;
extern UARTPort UARTPort2;

/**
 * 初始化为同步通信模式
 * @param uart 串口句柄
 * @param pinTxd TXD 引脚号
 * @param pinRxd RXD 引脚号
 * @param led 通信指示灯
 * @param txe 进入/退出 Tx 模式(针对 RS485 类型的通信，在开始发送数据之前，需使能发送)
 * @param mode 通信模式
 * @param baudrate 波特率
 * @param dataBits 数据位
 * @param stopBits 停止位
 * @param parity 校验位
 * @param onRxChar 字符流接收回调
 * @param onRxCharCookie 字符流接收回调cookie
 * @return
 */
esp_err_t UART_init(
	UARTPort uart, int pinTxd, int pinRxd, void *led, FUNC_void_u8 txe, uart_mode_t mode,
	uint32_t baudrate, uart_word_length_t dataBits, uart_parity_t stopBits, uart_stop_bits_t parity,
	bool initForAsync);

/// @brief 关闭串口
void UART_close(UARTPort uart);

/// @brief 单字符同步输出
/// @return <0: 错误；>=0，正常
int UART_putc(UARTPort uart, uint8_t ch);
/// @brief 单字符同步输入(最大等待时间1000ms)
/// @return <0: 错误；>=0，正常
int UART_getc(UARTPort uart, uint8_t *ch);

/// @brief 同步发送整个数据缓冲区
int UART_send(UARTPort uart, const void* data, int len);

/**
 * @brief 同步接收数据
 * @param uart 串口句柄
 * @param buff 接收数据缓冲区
 * @param buffSize 需要等待的最大响应字节数
 * @param okFlag OK情况下的响应数据标志
 * @param failedFlag 异常情况下的响应数据标志
 * @param timeoutTotal 响应的总超时时间(ms)
 * @param timeoutInterval 响应的数据字符间隔超时时间(ms)
 * @return <0 错误；>=0 接收到的数据长度
 * @attention: 注意：调用过程中会关闭串口的接收中断，防止数据被中断服务程序读走了
 */
int UART_receive(UARTPort uart, void* buff, int buffSize, const char *okFlag, const char *failedFlag, uint16_t timeoutTotal, uint16_t timeoutInterval);

/**
 * 发送指令并等待响应标志
 * @param uart 串口句柄
 * @param cmd 要发送的命令
 * @param buff 接收数据缓冲区
 * @param buffSize 需要等待的最大响应字节数
 * @param okFlag OK情况下的响应数据标志
 * @param failedFlag 异常情况下的响应数据标志
 * @param timeoutTotal 响应的总超时时间(ms)
 * @param timeoutInterval 响应的数据字符间隔超时时间(ms)
 * @return <0 错误；>=0 接收到的数据长度
 */
int UART_cmdResponse(UARTPort uart, char *cmd, void* buff, int buffSize, char *okFlag, char *failedFlag, uint16_t timeoutTotal, uint16_t timeoutInterval);

/// @brief 使能/禁用 RXNE 中断
esp_err_t UART_enableIrqRx(UARTPort uart, FUNC_UART_onRxChar onRxChar, const void *onRxCharCookie);
esp_err_t UART_disableIrqRx(UARTPort uart);

/// @brief 从字符串参数中解析串口配置参数
esp_err_t UART_parseParam(char* param, uart_config_t* config);
/// @brief 把串口配置参数输出为字符串参数
esp_err_t UART_packParam(uart_config_t* config, char* param);


#ifdef __cplusplus
}
#endif

#endif  // _UART_H_
/// @}
